﻿
function ApiController(viewModel, controllerName, overideUri) {
    var singular = false;
    var self = this;
    self.templateResponseText = null;
    self.element = null;
    self.templateLoaded = false;
    self.data = null;
    self.controllerName = controllerName;
    self.template = null;
    self.viewModel = viewModel;
    self.position = -1;
    self.newCount = 0;
    self.getListLimitedToIdentifier = false;
    self.isLoading = ko.observable(false);

    var defaultUri = config.contextPath + 'api/' + controllerName;
    var designatedUri = defaultUri;

    if (self.viewModel.selectedEntity != null) {
        self.viewModel.selectedEntity.subscribe(function (newValue) {
            self.addDirtyFlag(newValue);
        });
    }

    self.getDirtyFlag = function (entity) {
        if (entity != null && entity.dirtyFlag == null) {
            return false;
        }
        else {
            return entity.dirtyFlag.isDirty()
        }
    }

    self.addDirtyFlag = function (entity) {
        if (entity != null && entity.dirtyFlag == null) {
            entity.dirtyFlag = new ko.dirtyFlag(entity);
        }
        return true;
    }

    if (overideUri != null && overideUri != undefined) {
        designatedUri = config.contextPath + 'api/' + overideUri;
        var ending = parseInt(designatedUri.substring(designatedUri.lastIndexOf("/") + 1));
        if (!isNaN(ending)) {
            singular = true;
        }
    }
    else {
        var designatedPath = location.pathname;
        var ending = parseInt(designatedPath.substring(designatedPath.lastIndexOf("/") + 1));
        if (!isNaN(ending)) {
            singular = true;
            self.baseUri += "/" + ending;
        }
    }

    self.selectEntity = function (entity) {
        var found = false;
        for (i = 0; i < self.viewModel.entities().length; i++) {
            if (self.viewModel.entities()[i].Id == null)
                break;
            if (self.viewModel.entities()[i].Id() == entity.Id()) {
                self.position = i;
                var selected = self.viewModel.entities()[i];
                self.viewModel.selectedEntity(selected);
                found = true;
                break;
            }
        }

        if (!found && (entity.Id == null || entity.Id() <= 0)) {
            self.viewModel.selectedEntity(entity);
        }
    }

    self.loadTemplate = function (successFunction) {
        window.PageController.viewController.transmittingStyle("display");
        window.PageController.viewController.savedStyle("hide");
        window.PageController.viewController.failedStyle("hide");
        window.PageController.viewController.deletedStyle("hide");
        if (!self.templateLoaded) {
            $.getJSON(self.baseUri + "/0", self.template)
            .fail(function (jqxhr, textStatus, error) {
                window.PageController.viewController.transmittingStyle("hide");
                window.PageController.viewController.failedStyle("display");
                logError(textStatus, error);
            })
            .success(function (data, textStatus, resultResponse) {
                window.PageController.viewController.transmittingStyle("hide");
                self.templateResponseText = resultResponse.responseText;
                self.observableobject = ko.mapping.fromJSON(self.templateResponseText);
                self.template = self.observableobject;
                self.templateLoaded = true;
                if (successFunction != undefined) {
                    successFunction(self.template);
                }
            });
        }
    }

    // Makes an initial call to the server to get the template and then creates them using the blank template
    self.addEntityProxy = function (variable1, variable2) {
        self.addEntity();
    }

    // Makes an initial call to the server to get the template and then creates them using the blank template
    self.addEntity = function (afterAddEntity, parameter0, templateOverride, collectionOverride) {
        window.PageController.viewController.transmittingStyle("hide");
        window.PageController.viewController.savedStyle("hide");
        window.PageController.viewController.failedStyle("hide");
        window.PageController.viewController.deletedStyle("hide");
        if (templateOverride == null && !self.templateLoaded) {
            $.getJSON(self.baseUri + "/0", self.template)
            .fail(function (jqxhr, textStatus, error) {
                logError(textStatus, error);
            })
            .success(function (data, result, resultResponse) {
                self.templateResponseText = resultResponse.responseText;
                var observableobject = ko.mapping.fromJSON(self.templateResponseText);
                var newTemplate = ko.mapping.fromJSON(self.templateResponseText);
                self.viewModel.entities.push(newTemplate);
                self.viewModel.selectedEntity(self.viewModel.entities()[self.viewModel.entities().length - 1]);
                self.viewModel.selectedEntity().Id(self.newCount++ * -1);
                self.viewModel.selectedEntity().AccountId(window.operatingAccountId);
                self.position = self.viewModel.entities().length - 1;
                self.templateLoaded = true;
                if (afterAddEntity != undefined) {
                    afterAddEntity(parameter0, self.viewModel.selectedEntity);
                }
            });
        }
        else {

            var templateJson = templateOverride != null ? ko.mapping.toJSON(templateOverride) : self.templateResponseText;

            var newTemplate = ko.mapping.fromJSON(templateJson);
            newTemplate.Id(self.newCount++ * -1);
            if (newTemplate.AccountId != null) {
                newTemplate.AccountId(window.operatingAccountId);
            }
            if (collectionOverride != null) {
                collectionOverride.push(newTemplate);
            }
            else {
                self.viewModel.entities.push(newTemplate);
                self.selectEntity(newTemplate);
            }

            if (afterAddEntity != undefined) {
                afterAddEntity(parameter0, self.viewModel.selectedEntity, newTemplate);
            }
        }
    }

    self.deleteEntity = function (item, itemIdOverride) {
        window.PageController.viewController.transmittingStyle("display");
        window.PageController.viewController.savedStyle("hide");
        window.PageController.viewController.failedStyle("hide");
        window.PageController.viewController.deletedStyle("hide");
        var deleteId = item != null ? item.Id() : self.viewModel.selectedEntity().Id();
        if (itemIdOverride != null) {
            deleteId = itemIdOverride;
        }

        $.ajax({ type: "DELETE", url: self.baseUri + '/' + deleteId })
            .fail(function (jqxhr, textStatus, error) {
                window.PageController.viewController.transmittingStyle("hide");
                window.PageController.viewController.failedStyle("display");
                logError(textStatus, error);
            })
            .success(function (data, textStatus, resultResponse) {
                window.PageController.viewController.deletedStyle("display");
                window.PageController.viewController.transmittingStyle("hide");
                self.viewModel.entities.remove(self.viewModel.selectedEntity());
                var newpos = self.position - 1;
                if (newpos < 0) {
                    newpos = 0;
                }
                if (self.viewModel.entities().length > 0) {
                    self.viewModel.selectedEntity(self.viewModel.entities()[newpos]);
                }
            });
    }

    self.baseUri = designatedUri;
    self.addToEntities = function (observableobject, result)
    {
        var oo = observableobject;
        //var r = result;
        //self.viewModel.selectedEntity().Blogs.push(observableobject);
    }

    self.update = function (viewModel, viewSet, item, resultFunction, updateSelectedEntity) {
        if (item == null) {
            item = self.viewModel.selectedEntity();
        }
        if (updateSelectedEntity == null) {
            updateSelectedEntity = true;
        }

        window.PageController.viewController.lastStatus("");
        window.PageController.viewController.transmittingStyle("display");
        window.PageController.viewController.savedStyle("hide");
        window.PageController.viewController.failedStyle("hide");
        window.PageController.viewController.deletedStyle("hide");

        var dirtyItemData = self.getDirtyData(item);

        var itemData = JSON.stringify(dirtyItemData, null, 2);

        if (self.IsCollection == null || self.IsCollection) {
            destinationUrl = self.baseUri + '/' + item.Id();
        }
        else {
            if (self.baseUri.indexOf("/" + item.Id()) == -1) {
                destinationUrl = self.baseUri + '/' + item.Id();
            }
            else {
                destinationUrl = self.baseUri;
            }
        }

        // clear the previous error state
        //pageController.displayModelStateError(self.viewModel, null);

        $.ajax({
            type: "POST",
            dataType: "json",
            contentType: "application/json",
            url: destinationUrl,
            data: itemData
        }).success(function (data, result, resultResponse) {

            var observableobject = ko.mapping.fromJSON(resultResponse.responseText);
            if (resultFunction == null && observableobject.ForwardUrl != null && observableobject.ForwardUrl() != null && observableobject.ForwardUrl().length > 0) {
                if (observableobject.ForwardUrl() == "RefreshPage") {
                    pageController.OpenPage(pageController.readCookie("ReturnUrl"));
                }
                else {
                    pageController.OpenPage(observableobject.ForwardUrl());
                }
            }
            else {
                window.PageController.viewController.transmittingStyle("hide");
                window.PageController.viewController.savedStyle("display");

                if (updateSelectedEntity && self.position != null && self.position > -1) {
                    self.viewModel.entities.setAt(self.position, observableobject);
                    self.selectEntity(observableobject);
                }

                if (resultFunction != null) {
                    resultFunction(observableobject, result);
                }

            }
        })
        .fail(function (jqxhr, textStatus, error) {
            window.PageController.viewController.transmittingStyle("hide");
            if (jqxhr.responseJSON != null && jqxhr.responseJSON.ModelState != null) {
                viewController.displayModelStateError(self.viewModel, jqxhr.responseJSON);
                $("#submitButton").css({ opacity: 1.0 });
                $("#submitButton").prop('disabled', false);
            }
            else {
                window.PageController.viewController.failedStyle("display");
                logError(textStatus, error, jqxhr.responseText);
            }
        });
    }

    this.failureOnCall = function (error) {
        logError(textStatus, error);
    };

    self.populate = function (id, isCollection, data) {
        if (self.viewModel != null && self.viewModel.entities != null) {
            self.viewModel.entities.removeAll();
            if (isCollection != null && !isCollection) {
                self.viewModel.entities.push(ko.mapping.fromJS(data));
                var x = self.viewModel.entities()[0];
                //var t = self.viewModel.entities()[0]();
                self.selectEntity(self.viewModel.entities()[0]);
            }
            else {
                $.each(data, function (i, item) {
                    var viewModelItem = ko.mapping.fromJS(item);
                    self.viewModel.entities.push(viewModelItem);
                });
            }
        }


    }

    self.callUrl = function (uri, failFunction, successFunction, parameter0, parameter1) {
        var url = uri + '?' + (Math.random()).toString();
        $.getJSON(url, function (data) {
        }).fail(function (jqxhr, textStatus, error) {
            window.PageController.viewController.transmittingStyle("hide");
            window.PageController.viewController.failedStyle("display");
            logError(textStatus, error);
            if (failFunction != undefined) {
                failFunction(parameter0, parameter1);
            }
        })
         .success(function (o1, o2, o3) {
             window.PageController.viewController.transmittingStyle("hide");

             if (successFunction != undefined) {
                 successFunction(o1, o2, parameter0, parameter1);
             }
         });
    }

    self.getList = function (id, isCollection, successFunction, parameter0, parameter1, destinationEntities, dontRemoveAll) {
        window.PageController.viewController.lastStatus("");
        self.IsCollection = isCollection;

        if (window != null && window.PageController.viewController != null && window.PageController.viewController.transmittingStyle != null) {
            window.PageController.viewController.transmittingStyle("display");
        }

        uri = self.baseUri;
        if (destinationEntities != null) {
            destination = destinationEntities;
        }
        else {
            destination = self.viewModel.entities;
        }

        if (dontRemoveAll == null || !dontRemoveAll) {
            destination.removeAll();
        }
        if (isCollection != null && !isCollection) {
            destination = self.viewModel.selectedEntity;
        }

        if (id != null) {
            uri += "/" + id;
        }
        else if (self.getListLimitedToIdentifier) {
            uri += "/" + window.DefaultViewController.itemIdentifier;
        }
        var results;

        $.getJSON(uri, function (data) {
            self.populate(id, isCollection, data);
        }).fail(function (jqxhr, textStatus, error) {
            window.PageController.viewController.transmittingStyle("hide");
            window.PageController.viewController.failedStyle("display");
            logError(textStatus, error);
        })
            .success(function (o1, o2, o3) {
                window.PageController.viewController.transmittingStyle("hide");
                if (self.viewModel.selectedEntity != null && self.viewModel.selectedEntity() != null && self.viewModel.selectedEntity().Id() > 0) {
                    self.selectEntity(self.viewModel.selectedEntity());
                }
                if (successFunction != undefined) {
                    if (parameter1 == null) {
                        parameter1 = o1;
                    }
                    successFunction(parameter0, parameter1);
                }
            });
    }

    self.bindPage = function (formElement) {
        ko.cleanNode(window.document);
        ko.applyBindings(self);
    }

    self.getDirtyData = function (element) {
        var itemData = ko.toJS(element);
        self.iterateJson(element, null, itemData, 0);
        return itemData;
    }

    self.CheckForDirtyChildren = function (itemData) {
        for (var key in itemData) {
            var item = itemData[key];
            if (typeof itemData[key] === 'object' && itemData[key] != null) {
                if (key.indexOf('_') == 0) {
                    itemData[key] = null;
                }
                else {
                    for (var t = 0; t < itemData[key].length; t++) {
                        var item = itemData[key][t];
                        if (item.IsDirty) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    self.iterateJson = function (viewModel, itemDataOwner, itemData, level) {
        var newlevel = level + 1;
        for (var key in itemData) {
            var item = itemData[key];
            if (typeof itemData[key] === 'object' && itemData[key] != null) {
                if (key.indexOf('_') == 0) {
                    itemData[key] = null;
                }
                else {

                    if (viewModel != null && viewModel[key] != null) {
                        var object = eval("viewModel." + key);

                        if (typeof (object) == "function") {
                            var objCollection = eval("viewModel." + key + "()");
                            var nonFilterSubItems = ko.toJS(objCollection);
                            for (var i = 0; i < nonFilterSubItems.length; i++) {
                                var isDirty = self.CheckForDirtyChildren(nonFilterSubItems[i])
                                if (isDirty) {
                                    objCollection[i].IsDirty(true);
                                }
                            }


                            // get a list of objects that are dirty
                            var subitems = ko.utils.arrayFilter(objCollection, function (item) {
                                return item.IsDirty == null ? false : item.IsDirty();
                            });

                            // prune children and re-attach
                            var jsSubItems = ko.toJS(subitems);
                            // moderate sub items
                            for (var i = 0; i < jsSubItems.length; i++) {
                                var subitem = jsSubItems[i];
                                for (var n = 0; n < objCollection.length; n++) {
                                    var viewmodelItem = objCollection[n];
                                    var id = viewmodelItem.Id();
                                    var id2 = subitem.Id;
                                    if (viewmodelItem.Id() == subitem.Id) {
                                        self.iterateJson(viewmodelItem, subitem, level);
                                        break;
                                    }
                                }
                            }
                            itemData[key] = jsSubItems;
                            var elem = itemData[key];
                        }
                    }

                    self.iterateJson(object, itemData, itemData[key], level);

                }
            }
        }
    }

    self.notifyRenderComplete = function (element) {
        $('#renderArea').show();
        window.PageController.viewController.transmittingStyle("hide");
    }

    self.bindElement = function (element) {
        self.element = element;
        ko.cleanNode(element);
        ko.applyBindings(self.viewModel, element);
    }

}